

<!--
  规范：写明组件名称
  分页组件
-->
<pagination>

  <ul class="pagination">
    <li show={hasPrevPage}>
      <a href="javascript:;" onclick={ev.jumpPage}>1</a>
    </li>
    <li show={hasPrevPage}>
      <a href="javascript:;" onclick={ev.prevPage}>
        &lt;
      </a>
    </li>
    <li show={hasPrevSpan}>...</li>
    <li each={p in prevPages} no-reorder>
      <a href="javascript:;" onclick={ev.jumpPage}>{p}</a>
    </li>
    <li class="active">
      <a href="javascript:;">{page}</a>
    </li>
    <li each={p in nextPages} no-reorder>
      <a href="javascript:;" onclick={ev.jumpPage}>{p}</a>
    </li>
    <li show={hasNextSpan}>...</li>
    <li if={hasNextPage}>
      <a href="javascript:;" onclick={ev.nextPage}>
        &gt;
      </a>
    </li>
    <li show={hasNextPage}>
      <a href="javascript:;" onclick={ev.jumpPage}>{pages}</a>
    </li>
    <li class="select" if={opts.select=='y'}>
      跳转至
      <span if={pageList.length<100}>
        <select onchange={ev.jumpPage}>
          <option each={p in pageList} value={p} selected={p==page} no-reorder>{p}</option>
        </select>
      </span>
      <input if={pageList.length>=100} onchange={ev.jumpPage} type="number" value={page}> / {pages} 页
    </li>
  </ul>

  <script>

  /**
   * 规范：组件可传入参数需要在 script 头部注释说明
   * pages=总页数
   * page=当前页
   * span=前后页显示范围
   * select=y 的时候显示下拉分页
   * on-change=当组件页面发生变化触发的函数
   */

  /**
   * 规范：使用tag来代替_this , self, that 此类名称
   * 理由：组件挂载后变为riot tag 对象，用tag更贴切
   *      也便于跟函数内可能用到的类似变量做区分
   */
  var tag = this;

  /**
   * 规范：在挂载前预设的变量
   */
  tag.page = 1;
  tag.pages = 1;
  tag.pageSpan = 4;
  tag.pageList = [];

  /**
   * 规范：属于组件html内dom事件的函数放在 tag.ev
   * 每个函数上需要注释出用途
   */
  tag.ev = {

    // 跳转页
    jumpPage: function(e) {
      tag.fn.page(Number(
        e.item ? e.item.p :
        e.target.value || e.target.innerText
      ));
    },

    // 上一页
    prevPage: function() {
      if(tag.hasPrevPage)
      tag.fn.page(tag.page - 1);
    },

    // 下一页
    nextPage: function() {
      if(tag.hasNextPage)
      tag.fn.page(tag.page + 1);
    }

  };

  /**
   * 规范：组件内部的函数放入 tag.fn
   * 每个函数上需要注释出用途
   */
  tag.fn = {

    // 根据 opts.pages 生成分页列表
    pageList: function() {
      tag.pageList = [];
      for(var page = 1; page <= tag.pages; page++){
        tag.pageList.push(page);
      }
    },

    // 根据 opts.span 跟当前页面计算出往前可以显示多少页
    prevPages: function() {
      var i = tag.pageSpan;
      tag.hasPrevSpan = (tag.page - tag.pageSpan) > 0;
      tag.prevPages = [];
      while(i--){
        if(tag.page - i > 1 && i > 0){
          tag.prevPages.push(tag.page - i);
        }
      }
    },

    // 同理根据 opts.span 计算往后显示页面
    nextPages: function() {
      var i = 0;
      tag.hasNextSpan = (tag.page + tag.pageSpan) < tag.pages;
      tag.nextPages = [];
      while(++i < tag.pageSpan){
        if(tag.page + i < tag.pages){
          tag.nextPages.push(tag.page + i);
        }
      }
    },

    // 几个分页变量的统一计算
    pageCount: function(){
      tag.hasNextPage = tag.pages > tag.page;
      tag.hasPrevPage = tag.page > 1;
      tag.fn.prevPages();
      tag.fn.nextPages();
    },

    // 切换页面
    page: function(n) {
      opts.onChange && opts.onChange(n);
    },

    render: function(page, pages){
      tag.page = Number(page);
      if(pages){
        tag.pages = Number(pages);
        tag.fn.pageList();
      }
      tag.fn.pageCount();
    }

  };

  tag.on('mount', function(){
    tag.fn.render(opts.page, opts.pages);
  });

  tag.on('update', function(){
    // console.log('update');
    tag.fn.render(opts.page, opts.pages);
  });

  // 什么情况下 update 提高效率
  shouldUpdate(data, nextOpts){
    return (tag.page != nextOpts.page || tag.pages != nextOpts.pages);
  }

  </script>

</pagination>
